home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 June / CHIP Haziran 2001.iso / prog / haziran / 19 / setup.exe / data.z / p9054_lib.c < prev    next >
C/C++ Source or Header  |  2001-04-11  |  31KB  |  1,033 lines

  1. ////////////////////////////////////////////////////////////////
  2. // File - P9054_LIB.C
  3. //
  4. // Library for 'WinDriver for PLX 9054' API. 
  5. // The basic idea is to get a handle for the board
  6. // with P9054_Open() and use it in the rest of the program
  7. // when calling WD functions.  Call P9054_Close() when done.
  8. // 
  9. ////////////////////////////////////////////////////////////////
  10.  
  11. #include "p9054_lib.h"
  12. #include "../../../include/windrvr_int_thread.h"
  13. #if !defined(__KERNEL__) 
  14.     #include <stdio.h>
  15. #endif
  16.  
  17. // this string is set to an error message, if one occurs
  18. CHAR P9054_ErrorString[1024];
  19.  
  20. // internal data structures and enums
  21. enum { P9054_DMA_CHANNEL_SHIFT = 0x14 }; // shift in address between channels 0 and 1 of DMA
  22.  
  23. typedef struct P9054_DMA_STRUCT{
  24.     WD_DMA dma;
  25.     WD_DMA dmaList;
  26.     P9054_DMA_CHANNEL dmaChannel;
  27. } P9054_DMA_STRUCT;
  28.  
  29. enum { P9054_MODE_DESC       = 0xF9000140 };
  30. enum { P9054_MODE_DESC_BYTE  = 0x00000000 };
  31. enum { P9054_MODE_DESC_WORD  = 0x00010001 };
  32. enum { P9054_MODE_DESC_DWORD = 0x00030003 };
  33.  
  34. typedef struct
  35. {
  36.     WD_INTERRUPT Int;
  37.     HANDLE hThread;
  38.     WD_TRANSFER Trans[2];
  39.     P9054_INT_HANDLER funcIntHandler;
  40. } P9054_INTERRUPT;
  41.  
  42. typedef struct 
  43. {
  44.     DWORD dwLocalBase;
  45.     DWORD dwMask;
  46.     DWORD dwBytes;
  47.     DWORD dwAddr;
  48.     DWORD dwAddrDirect;
  49.     BOOL  fIsMemory;
  50. } P9054_ADDR_DESC;
  51.  
  52. typedef struct P9054_STRUCT
  53. {
  54.     HANDLE hWD;
  55.     WD_CARD cardLock;
  56.     WD_PCI_SLOT pciSlot;
  57.     WD_CARD_REGISTER cardReg;
  58.     P9054_ADDR_DESC addrDesc[AD_PCI_BARS];
  59.     DWORD  addrSpace;
  60.     BOOL   fUseInt;
  61.     P9054_INTERRUPT Int;
  62. } P9054_STRUCT;
  63.  
  64.  
  65. // internal function used by P9054_Open()
  66. BOOL P9054_DetectCardElements(P9054_HANDLE hPlx);
  67. // internal function used by P9054_Read... and P9054_Write... functions
  68. void P9054_SetMode (P9054_HANDLE hPlx, P9054_MODE mode, DWORD dwLocalAddr);
  69.  
  70. DWORD P9054_CountCards (DWORD dwVendorID, DWORD dwDeviceID)
  71. {
  72.     WD_VERSION ver;
  73.     WD_PCI_SCAN_CARDS pciScan;
  74.     HANDLE hWD = INVALID_HANDLE_VALUE;
  75.  
  76.     P9054_ErrorString[0] = '\0';
  77.     hWD = WD_Open();
  78.     // check if handle valid & version OK
  79.     if (hWD==INVALID_HANDLE_VALUE) 
  80.     {
  81.         sprintf( P9054_ErrorString, "Failed opening " WD_PROD_NAME " device\n");
  82.         return 0;
  83.     }
  84.  
  85.     BZERO(ver);
  86.     WD_Version(hWD,&ver);
  87.     if (ver.dwVer<WD_VER) 
  88.     {
  89.         sprintf( P9054_ErrorString, "Incorrect " WD_PROD_NAME " version\n");
  90.         WD_Close (hWD);
  91.         return 0;
  92.     }
  93.  
  94.     BZERO(pciScan);
  95.     pciScan.searchId.dwVendorId = dwVendorID;
  96.     pciScan.searchId.dwDeviceId = dwDeviceID;
  97.     WD_PciScanCards (hWD, &pciScan);
  98.     WD_Close (hWD);
  99.     if (pciScan.dwCards==0)
  100.         sprintf( P9054_ErrorString, "no cards found\n");
  101.     return pciScan.dwCards;
  102. }
  103.  
  104.  
  105. BOOL P9054_Open (P9054_HANDLE *phPlx, DWORD dwVendorID, DWORD dwDeviceID, DWORD nCardNum, DWORD dwOptions)
  106. {
  107.     P9054_HANDLE hPlx = (P9054_HANDLE) malloc (sizeof (P9054_STRUCT));
  108.     DWORD dwIntStatus;
  109.  
  110.     WD_VERSION ver;
  111.     WD_PCI_SCAN_CARDS pciScan;
  112.     WD_PCI_CARD_INFO pciCardInfo;
  113.  
  114.     *phPlx = NULL;
  115.     P9054_ErrorString[0] = '\0';
  116.     BZERO(*hPlx);
  117.  
  118.     hPlx->hWD = WD_Open();
  119.  
  120.     // check if handle valid & version OK
  121.     if (hPlx->hWD==INVALID_HANDLE_VALUE) 
  122.     {
  123.         sprintf( P9054_ErrorString, "Failed opening " WD_PROD_NAME " device\n");
  124.         goto Exit;
  125.     }
  126.  
  127.     BZERO(ver);
  128.     WD_Version(hPlx->hWD,&ver);
  129.     if (ver.dwVer<WD_VER) 
  130.     {
  131.         sprintf( P9054_ErrorString, "Incorrect " WD_PROD_NAME " version\n");
  132.         goto Exit;
  133.     }
  134.  
  135.     BZERO(pciScan);
  136.     pciScan.searchId.dwVendorId = dwVendorID;
  137.     pciScan.searchId.dwDeviceId = dwDeviceID;
  138.     WD_PciScanCards (hPlx->hWD, &pciScan);
  139.     if (pciScan.dwCards==0) // Found at least one card
  140.     {
  141.         sprintf( P9054_ErrorString, "Could not find PCI card\n");
  142.         goto Exit;
  143.     }
  144.     if (pciScan.dwCards<=nCardNum)
  145.     {
  146.         sprintf( P9054_ErrorString, "Card out of range of available cards\n");
  147.         goto Exit;
  148.     }
  149.  
  150.     BZERO(pciCardInfo);
  151.     pciCardInfo.pciSlot = pciScan.cardSlot[nCardNum];
  152.     WD_PciGetCardInfo (hPlx->hWD, &pciCardInfo);
  153.     hPlx->pciSlot = pciCardInfo.pciSlot;
  154.     hPlx->cardReg.Card = pciCardInfo.Card;
  155.  
  156.     hPlx->fUseInt = (dwOptions & P9054_OPEN_USE_INT) ? TRUE : FALSE;
  157.     if (!hPlx->fUseInt)
  158.     {
  159.         DWORD i;
  160.         // Remove interrupt item if not needed
  161.         for (i=0; i<hPlx->cardReg.Card.dwItems; i++)
  162.         {
  163.             WD_ITEMS *pItem = &hPlx->cardReg.Card.Item[i];
  164.             if (pItem->item==ITEM_INTERRUPT)
  165.                 pItem->item = ITEM_NONE;
  166.         }
  167.     }
  168.     else
  169.     {
  170.         DWORD i;
  171.         // make interrupt resource sharable
  172.         for (i=0; i<hPlx->cardReg.Card.dwItems; i++)
  173.         {
  174.             WD_ITEMS *pItem = &hPlx->cardReg.Card.Item[i];
  175.             if (pItem->item==ITEM_INTERRUPT)
  176.                 pItem->fNotSharable = FALSE;
  177.         }
  178.     }
  179.  
  180.     hPlx->cardReg.fCheckLockOnly = FALSE;
  181.     WD_CardRegister (hPlx->hWD, &hPlx->cardReg);
  182.     if (hPlx->cardReg.hCard==0)
  183.     {
  184.         sprintf ( P9054_ErrorString, "Failed locking device\n");
  185.         goto Exit;
  186.     }
  187.  
  188.     if (!P9054_DetectCardElements(hPlx))
  189.     {
  190.         sprintf ( P9054_ErrorString, "Card does not have all items expected for PLX 9054\n");
  191.         goto Exit;
  192.     }
  193.  
  194.     // this enables target abort so it wont get stuck 
  195.     dwIntStatus = P9054_ReadReg (hPlx, P9054_INTCSR);
  196.     P9054_WriteReg (hPlx, P9054_INTCSR, dwIntStatus | BIT12);
  197.  
  198.     // Open finished OK
  199.     *phPlx = hPlx;
  200.     return TRUE;
  201.  
  202. Exit:
  203.     // Error durin Open
  204.     if (hPlx->cardReg.hCard) 
  205.         WD_CardUnregister(hPlx->hWD, &hPlx->cardReg);
  206.     if (hPlx->hWD!=INVALID_HANDLE_VALUE)
  207.         WD_Close(hPlx->hWD);
  208.     free (hPlx);
  209.     return FALSE;
  210. }
  211.  
  212. void P9054_GetPciSlot(P9054_HANDLE hPlx, WD_PCI_SLOT *pPciSlot)
  213. {
  214.     *pPciSlot = hPlx->pciSlot;
  215. }
  216.  
  217. DWORD P9054_ReadPCIReg(P9054_HANDLE hPlx, DWORD dwReg)
  218. {
  219.     WD_PCI_CONFIG_DUMP pciCnf;
  220.     DWORD dwVal;
  221.  
  222.     BZERO (pciCnf);
  223.     pciCnf.pciSlot = hPlx->pciSlot;
  224.     pciCnf.pBuffer = &dwVal;
  225.     pciCnf.dwOffset = dwReg;
  226.     pciCnf.dwBytes = 4;
  227.     pciCnf.fIsRead = TRUE;
  228.     WD_PciConfigDump(hPlx->hWD,&pciCnf);
  229.     return dwVal;
  230. }
  231.  
  232. void P9054_WritePCIReg(P9054_HANDLE hPlx, DWORD dwReg, DWORD dwData)
  233. {
  234.     WD_PCI_CONFIG_DUMP pciCnf;
  235.  
  236.     BZERO (pciCnf);
  237.     pciCnf.pciSlot = hPlx->pciSlot;
  238.     pciCnf.pBuffer = &dwData;
  239.     pciCnf.dwOffset = dwReg;
  240.     pciCnf.dwBytes = 4;
  241.     pciCnf.fIsRead = FALSE;
  242.     WD_PciConfigDump(hPlx->hWD,&pciCnf);
  243. }
  244.  
  245. BOOL P9054_DetectCardElements(P9054_HANDLE hPlx)
  246. {
  247.     DWORD i;
  248.     DWORD ad_sp;
  249.  
  250.     BZERO(hPlx->Int);
  251.     BZERO(hPlx->addrDesc);
  252.  
  253.     for (i=0; i<hPlx->cardReg.Card.dwItems; i++)
  254.     {
  255.         WD_ITEMS *pItem = &hPlx->cardReg.Card.Item[i];
  256.  
  257.         switch (pItem->item)
  258.         {
  259.         case ITEM_MEMORY:
  260.         case ITEM_IO:
  261.             {
  262.                 DWORD dwBytes;
  263.                 DWORD dwAddr;
  264.                 DWORD dwPhysAddr;
  265.                 DWORD dwAddrDirect = 0;
  266.                 BOOL fIsMemory;
  267.                 if (pItem->item==ITEM_MEMORY)
  268.                 {
  269.                     dwBytes = pItem->I.Mem.dwBytes;
  270.                     dwAddr = pItem->I.Mem.dwTransAddr;
  271.                     dwAddrDirect = pItem->I.Mem.dwUserDirectAddr;
  272.                     dwPhysAddr = pItem->I.Mem.dwPhysicalAddr;
  273.                     fIsMemory = TRUE;
  274.                 }
  275.                 else 
  276.                 {
  277.                     dwBytes = pItem->I.IO.dwBytes;
  278.                     dwAddr = pItem->I.IO.dwAddr;
  279.                     dwPhysAddr = dwAddr & 0xffff;
  280.                     fIsMemory = FALSE;
  281.                 }
  282.  
  283.                 for (ad_sp=P9054_ADDR_REG; ad_sp<=P9054_ADDR_EPROM; ad_sp++)
  284.                 {
  285.                     DWORD dwPCIAddr;
  286.                     DWORD dwPCIReg;
  287.  
  288.                     if (hPlx->addrDesc[ad_sp].dwAddr) continue;
  289.                     if (ad_sp==P9054_ADDR_REG) dwPCIReg = PCI_BAR0;
  290.                     else if (ad_sp<P9054_ADDR_EPROM) 
  291.                         dwPCIReg = PCI_BAR2 + 4*(ad_sp-P9054_ADDR_SPACE0);
  292.                     else dwPCIReg = PCI_ERBAR;
  293.                     dwPCIAddr = P9054_ReadPCIReg(hPlx, dwPCIReg);
  294.                     if (dwPCIAddr & 1)
  295.                     {
  296.                         if (fIsMemory) continue;
  297.                         dwPCIAddr &= ~0x3;
  298.                     }
  299.                     else
  300.                     {
  301.                         if (!fIsMemory) continue;
  302.                         dwPCIAddr &= ~0xf;
  303.                     }
  304.                     if (dwPCIAddr==dwPhysAddr)
  305.                         break;
  306.                 }
  307.                 if (ad_sp<=P9054_ADDR_EPROM)
  308.                 {
  309.                     DWORD j;
  310.                     hPlx->addrDesc[ad_sp].dwBytes = dwBytes;
  311.                     hPlx->addrDesc[ad_sp].dwAddr = dwAddr;
  312.                     hPlx->addrDesc[ad_sp].dwAddrDirect = dwAddrDirect;
  313.                     hPlx->addrDesc[ad_sp].fIsMemory = fIsMemory;
  314.                     hPlx->addrDesc[ad_sp].dwMask = 0;
  315.                     for (j=1; j<hPlx->addrDesc[ad_sp].dwBytes && j!=0x80000000; j *= 2)
  316.                     {
  317.                         hPlx->addrDesc[ad_sp].dwMask = 
  318.                             (hPlx->addrDesc[ad_sp].dwMask << 1) | 1;
  319.                     }
  320.                 }
  321.             }
  322.             break;
  323.         case ITEM_INTERRUPT:
  324.             if (hPlx->Int.Int.hInterrupt) return FALSE;
  325.             hPlx->Int.Int.hInterrupt = pItem->I.Int.hInterrupt;
  326.             break;
  327.         }
  328.     }
  329.  
  330.     // check that all the items needed were found
  331.     // check if interrupt found
  332.     if (hPlx->fUseInt && !hPlx->Int.Int.hInterrupt) 
  333.     {
  334.         return FALSE;
  335.     }
  336.  
  337.     // check that the registers space was found
  338.     if (!P9054_IsAddrSpaceActive(hPlx, P9054_ADDR_REG)) 
  339.             //|| hPlx->addrDesc[P9054_ADDR_REG].dwBytes!=P9054_RANGE_REG)
  340.         return FALSE;
  341.  
  342.     // use address space 0 for accessing local addresses
  343.     hPlx->addrSpace = P9054_ADDR_SPACE0;
  344.     
  345.     // check that address space 0 was found
  346.     if (!P9054_IsAddrSpaceActive(hPlx, hPlx->addrSpace)) return FALSE;
  347.  
  348.     return TRUE;
  349. }
  350.  
  351. void P9054_Close(P9054_HANDLE hPlx)
  352. {
  353.     // disable interrupts
  354.     if (P9054_IntIsEnabled(hPlx))
  355.         P9054_IntDisable(hPlx);
  356.  
  357.     // unregister card
  358.     if (hPlx->cardReg.hCard) 
  359.         WD_CardUnregister(hPlx->hWD, &hPlx->cardReg);
  360.  
  361.     // close WinDriver
  362.     WD_Close(hPlx->hWD);
  363.  
  364.     free (hPlx);
  365. }
  366.  
  367. BOOL P9054_IsAddrSpaceActive(P9054_HANDLE hPlx, P9054_ADDR addrSpace)
  368. {
  369.     return hPlx->addrDesc[addrSpace].dwAddr!=0;
  370. }
  371.  
  372. DWORD P9054_ReadReg (P9054_HANDLE hPlx, DWORD dwReg)
  373. {
  374.     return P9054_ReadDWord(hPlx, P9054_ADDR_REG, dwReg);
  375. }
  376.  
  377. void P9054_WriteReg (P9054_HANDLE hPlx, DWORD dwReg, DWORD dwData)
  378. {
  379.     P9054_WriteDWord(hPlx, P9054_ADDR_REG, dwReg, dwData);
  380. }
  381.  
  382. BYTE P9054_ReadByte (P9054_HANDLE hPlx, P9054_ADDR addrSpace, DWORD dwOffset)
  383. {
  384.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  385.     {
  386.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  387.         BYTE *pByte = (BYTE *) dwAddr;
  388.         return *pByte;
  389.     }
  390.     else
  391.     {
  392.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  393.         WD_TRANSFER trans;
  394.         BZERO(trans);
  395.         trans.cmdTrans = RP_BYTE;
  396.         trans.dwPort = dwAddr;
  397.         WD_Transfer (hPlx->hWD, &trans);
  398.         return trans.Data.Byte;
  399.     }
  400. }
  401.  
  402. void P9054_WriteByte (P9054_HANDLE hPlx, P9054_ADDR addrSpace, DWORD dwOffset,
  403.     BYTE data)
  404. {
  405.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  406.     {
  407.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  408.         BYTE *pByte = (BYTE *) dwAddr;
  409.         *pByte = data;
  410.     }
  411.     else
  412.     {
  413.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  414.         WD_TRANSFER trans;
  415.         BZERO(trans);
  416.         trans.cmdTrans = WP_BYTE;
  417.         trans.dwPort = dwAddr;
  418.         trans.Data.Byte = data;
  419.         WD_Transfer (hPlx->hWD, &trans);
  420.     }
  421. }
  422.  
  423. WORD P9054_ReadWord (P9054_HANDLE hPlx, P9054_ADDR addrSpace, DWORD dwOffset)
  424. {
  425.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  426.     {
  427.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  428.         WORD *pWord = (WORD *) dwAddr;
  429.         return *pWord;
  430.     }
  431.     else
  432.     {
  433.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  434.         WD_TRANSFER trans;
  435.         BZERO(trans);
  436.         trans.cmdTrans = RP_WORD;
  437.         trans.dwPort = dwAddr;
  438.         WD_Transfer (hPlx->hWD, &trans);
  439.         return trans.Data.Word;
  440.     }
  441. }
  442.  
  443. void P9054_WriteWord (P9054_HANDLE hPlx, P9054_ADDR addrSpace, DWORD dwOffset, WORD data)
  444. {
  445.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  446.     {
  447.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  448.         WORD *pWord = (WORD *) dwAddr;
  449.         *pWord = data;
  450.     }
  451.     else
  452.     {
  453.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  454.         WD_TRANSFER trans;
  455.         BZERO(trans);
  456.         trans.cmdTrans = WP_WORD;
  457.         trans.dwPort = dwAddr;
  458.         trans.Data.Word = data;
  459.         WD_Transfer (hPlx->hWD, &trans);
  460.     }
  461. }
  462.  
  463. DWORD P9054_ReadDWord (P9054_HANDLE hPlx, P9054_ADDR addrSpace, DWORD dwOffset)
  464. {
  465.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  466.     {
  467.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  468.         DWORD *pDword = (DWORD *) dwAddr;
  469.         return *pDword;
  470.     }
  471.     else
  472.     {
  473.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  474.         WD_TRANSFER trans;
  475.         BZERO(trans);
  476.         trans.cmdTrans = RP_DWORD;
  477.         trans.dwPort = dwAddr;
  478.         WD_Transfer (hPlx->hWD, &trans);
  479.         return trans.Data.Dword;
  480.     }
  481. }
  482.  
  483. void P9054_WriteDWord (P9054_HANDLE hPlx, P9054_ADDR addrSpace, DWORD dwOffset, DWORD data)
  484. {
  485.     if (hPlx->addrDesc[addrSpace].fIsMemory)
  486.     {
  487.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddrDirect + dwOffset;
  488.         DWORD *pDword = (DWORD *) dwAddr;
  489.         *pDword = data;
  490.     }
  491.     else
  492.     {
  493.         DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  494.         WD_TRANSFER trans;
  495.         BZERO(trans);
  496.         trans.cmdTrans = WP_DWORD;
  497.         trans.dwPort = dwAddr;
  498.         trans.Data.Dword = data;
  499.         WD_Transfer (hPlx->hWD, &trans);
  500.     }
  501. }
  502.  
  503. void P9054_ReadWriteBlock (P9054_HANDLE hPlx, DWORD dwOffset, PVOID buf, 
  504.                     DWORD dwBytes, BOOL fIsRead, P9054_ADDR addrSpace, P9054_MODE mode)
  505. {
  506.     DWORD dwAddr = hPlx->addrDesc[addrSpace].dwAddr + dwOffset;
  507.     WD_TRANSFER trans;
  508.  
  509.     BZERO(trans);
  510.  
  511.     if (hPlx->addrDesc[addrSpace].fIsMemory) 
  512.     {
  513.         if (fIsRead) 
  514.         {
  515.             if (mode==P9054_MODE_BYTE) trans.cmdTrans = RM_SBYTE;
  516.             else if (mode==P9054_MODE_WORD) trans.cmdTrans = RM_SWORD;
  517.             else trans.cmdTrans = RM_SDWORD;
  518.         }
  519.         else 
  520.         {
  521.             if (mode==P9054_MODE_BYTE) trans.cmdTrans = WM_SBYTE;
  522.             else if (mode==P9054_MODE_WORD) trans.cmdTrans = WM_SWORD;
  523.             else trans.cmdTrans = WM_SDWORD;
  524.         }
  525.     }
  526.     else 
  527.     {
  528.         if (fIsRead) 
  529.         {
  530.             if (mode==P9054_MODE_BYTE) trans.cmdTrans = RP_SBYTE;
  531.             else if (mode==P9054_MODE_WORD) trans.cmdTrans = RP_SWORD;
  532.             else trans.cmdTrans = RP_SDWORD;
  533.         }
  534.         else 
  535.         {
  536.             if (mode==P9054_MODE_BYTE) trans.cmdTrans = WP_SBYTE;
  537.             else if (mode==P9054_MODE_WORD) trans.cmdTrans = WP_SWORD;
  538.             else trans.cmdTrans = WP_SDWORD;
  539.         }
  540.     }
  541.     trans.dwPort = dwAddr;
  542.     trans.fAutoinc = TRUE;
  543.     trans.dwBytes = dwBytes;
  544.     trans.dwOptions = 0;
  545.     trans.Data.pBuffer = buf;
  546.     WD_Transfer (hPlx->hWD, &trans);
  547. }
  548.  
  549. void P9054_ReadBlock (P9054_HANDLE hPlx, DWORD dwOffset, PVOID buf, 
  550.                     DWORD dwBytes, P9054_ADDR addrSpace, P9054_MODE mode)
  551. {
  552.     P9054_ReadWriteBlock (hPlx, dwOffset, buf, dwBytes, TRUE, addrSpace, mode);
  553. }
  554.  
  555. void P9054_WriteBlock (P9054_HANDLE hPlx, DWORD dwOffset, PVOID buf, 
  556.                      DWORD dwBytes, P9054_ADDR addrSpace, P9054_MODE mode)
  557. {
  558.     P9054_ReadWriteBlock (hPlx, dwOffset, buf, dwBytes, FALSE, addrSpace, mode);
  559. }
  560.  
  561. void P9054_SetMode (P9054_HANDLE hPlx, P9054_MODE mode, DWORD dwLocalAddr)
  562. {
  563.     hPlx->addrDesc[hPlx->addrSpace].dwLocalBase = dwLocalAddr & ~hPlx->addrDesc[hPlx->addrSpace].dwMask;
  564.     hPlx->addrDesc[hPlx->addrSpace].dwLocalBase |= BIT0;
  565.     P9054_WriteReg (hPlx, P9054_LAS0BA, hPlx->addrDesc[hPlx->addrSpace].dwLocalBase);
  566. }
  567.  
  568. BYTE P9054_ReadByteLocal (P9054_HANDLE hPlx, DWORD dwLocalAddr)
  569. {
  570.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  571.     P9054_SetMode (hPlx, P9054_MODE_BYTE, dwLocalAddr);
  572.     return P9054_ReadByte(hPlx, hPlx->addrSpace, dwOffset);
  573. }
  574.  
  575. void P9054_WriteByteLocal (P9054_HANDLE hPlx, DWORD dwLocalAddr, BYTE data)
  576. {
  577.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  578.     P9054_SetMode (hPlx, P9054_MODE_BYTE, dwLocalAddr);
  579.     P9054_WriteByte(hPlx, hPlx->addrSpace, dwOffset, data);
  580. }
  581.  
  582. WORD P9054_ReadWordLocal (P9054_HANDLE hPlx, DWORD dwLocalAddr)
  583. {
  584.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  585.     P9054_SetMode (hPlx, P9054_MODE_WORD, dwLocalAddr);
  586.     return P9054_ReadWord(hPlx, hPlx->addrSpace, dwOffset);
  587. }
  588.  
  589. void P9054_WriteWordLocal (P9054_HANDLE hPlx, DWORD dwLocalAddr, WORD data)
  590. {
  591.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  592.     P9054_SetMode (hPlx, P9054_MODE_WORD, dwLocalAddr);
  593.     P9054_WriteWord(hPlx, hPlx->addrSpace, dwOffset, data);
  594. }
  595.  
  596. DWORD P9054_ReadDWordLocal (P9054_HANDLE hPlx, DWORD dwLocalAddr)
  597. {
  598.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  599.     P9054_SetMode (hPlx, P9054_MODE_DWORD, dwLocalAddr);
  600.     return P9054_ReadDWord(hPlx, hPlx->addrSpace, dwOffset);
  601. }
  602.  
  603. void P9054_WriteDWordLocal (P9054_HANDLE hPlx, DWORD dwLocalAddr, DWORD data)
  604. {
  605.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  606.     P9054_SetMode (hPlx, P9054_MODE_DWORD, dwLocalAddr);
  607.     P9054_WriteDWord(hPlx, hPlx->addrSpace, dwOffset, data);
  608. }
  609.  
  610. void P9054_ReadWriteBlockLocal (P9054_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  611.                     DWORD dwBytes, BOOL fIsRead, P9054_MODE mode)
  612. {
  613.     DWORD dwOffset = hPlx->addrDesc[hPlx->addrSpace].dwMask & dwLocalAddr;
  614.     P9054_SetMode (hPlx, mode, dwLocalAddr);
  615.     P9054_ReadWriteBlock(hPlx, dwOffset, buf, dwBytes, fIsRead, hPlx->addrSpace, mode);
  616. }
  617.  
  618. void P9054_ReadBlockLocal (P9054_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  619.                     DWORD dwBytes, P9054_MODE mode)
  620. {
  621.     P9054_ReadWriteBlockLocal (hPlx, dwLocalAddr, buf, dwBytes, TRUE, mode);
  622. }
  623.  
  624. void P9054_WriteBlockLocal (P9054_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  625.                      DWORD dwBytes, P9054_MODE mode)
  626. {
  627.     P9054_ReadWriteBlockLocal (hPlx, dwLocalAddr, buf, dwBytes, FALSE, mode);
  628. }
  629.  
  630. BOOL P9054_IntIsEnabled (P9054_HANDLE hPlx)
  631. {
  632.     if (!hPlx->fUseInt) return FALSE;
  633.     if (!hPlx->Int.hThread) return FALSE;
  634.     return TRUE;
  635. }
  636.  
  637. VOID P9054_IntHandler (PVOID pData)
  638. {
  639.     P9054_HANDLE hPlx = (P9054_HANDLE) pData;
  640.     P9054_INT_RESULT intResult;
  641.     intResult.dwCounter = hPlx->Int.Int.dwCounter;
  642.     intResult.dwLost = hPlx->Int.Int.dwLost;
  643.     intResult.fStopped = hPlx->Int.Int.fStopped;
  644.     intResult.dwStatusReg = hPlx->Int.Trans[0].Data.Dword;
  645.     hPlx->Int.funcIntHandler(hPlx, &intResult);  
  646. }
  647.  
  648. BOOL P9054_IntEnable (P9054_HANDLE hPlx, P9054_INT_HANDLER funcIntHandler)
  649. {
  650.     DWORD dwIntStatus;
  651.     DWORD dwAddr;
  652.  
  653.     if (!hPlx->fUseInt) return FALSE;
  654.     // check if interrupt is already enabled
  655.     if (hPlx->Int.hThread) return FALSE;
  656.  
  657.     dwIntStatus = P9054_ReadReg (hPlx, P9054_INTCSR);
  658.  
  659.     BZERO(hPlx->Int.Trans);
  660.     // This is a samlpe of handling interrupts:
  661.     // Two transfer commands are issued. First the value of the interrrupt control/status
  662.     // register is read. Then, a value of ZERO is written.
  663.     // This will cancel interrupts after the first interrupt occurs.
  664.     // When using interrupts, this section will have to change:
  665.     // you must put transfer commands to CANCEL the source of the interrupt, otherwise, the 
  666.     // PC will hang when an interrupt occurs!
  667.     dwAddr = hPlx->addrDesc[P9054_ADDR_REG].dwAddr + P9054_INTCSR;
  668.     hPlx->Int.Trans[0].cmdTrans = hPlx->addrDesc[P9054_ADDR_REG].fIsMemory ? RM_DWORD : RP_DWORD;
  669.     hPlx->Int.Trans[0].dwPort = dwAddr;
  670.     hPlx->Int.Trans[1].cmdTrans = hPlx->addrDesc[P9054_ADDR_REG].fIsMemory ? WM_DWORD : WP_DWORD;
  671.     hPlx->Int.Trans[1].dwPort = dwAddr;
  672.     hPlx->Int.Trans[1].Data.Dword = dwIntStatus & ~(BIT8|BIT10); // put here the data to write to the control register
  673.     hPlx->Int.Int.dwCmds = 2; 
  674.     hPlx->Int.Int.Cmd = hPlx->Int.Trans;
  675.     hPlx->Int.Int.dwOptions |= INTERRUPT_CMD_COPY;
  676.  
  677.     // this calls WD_IntEnable() and creates an interrupt handler thread
  678.     hPlx->Int.funcIntHandler = funcIntHandler;
  679.     if (!InterruptThreadEnable(&hPlx->Int.hThread, hPlx->hWD, &hPlx->Int.Int, P9054_IntHandler, (PVOID) hPlx))
  680.         return FALSE;
  681.  
  682.     // this physically enables interrupts
  683.     P9054_WriteReg (hPlx, P9054_INTCSR, dwIntStatus | (BIT8|BIT10));
  684.  
  685.     return TRUE;
  686. }
  687.  
  688. void P9054_IntDisable (P9054_HANDLE hPlx)
  689. {
  690.     DWORD dwIntStatus;
  691.  
  692.     if (!hPlx->fUseInt) return;
  693.     if (!hPlx->Int.hThread) return;
  694.  
  695.     // this disables interrupts
  696.     dwIntStatus = P9054_ReadReg (hPlx, P9054_INTCSR);
  697.     P9054_WriteReg (hPlx, P9054_INTCSR, dwIntStatus & ~(BIT8|BIT10));
  698.  
  699.     // this calls WD_IntDisable()
  700.     InterruptThreadDisable(hPlx->Int.hThread);
  701.     hPlx->Int.hThread = NULL;
  702. }
  703.  
  704. P9054_DMA_HANDLE P9054_DMAOpen (P9054_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  705.     DWORD dwBytes, BOOL fIsRead, P9054_MODE mode, P9054_DMA_CHANNEL dmaChannel)
  706. {
  707.     DWORD dwDMAMODE, dwDMADPR, dwDMALADR;
  708.     DWORD dwChannelShift = (dmaChannel==P9054_DMA_CHANNEL_0) ? 0 : P9054_DMA_CHANNEL_SHIFT;
  709.     BOOL fAutoinc = TRUE;
  710.     P9054_DMA_HANDLE hDma;
  711.     
  712.     hDma = (P9054_DMA_HANDLE) malloc (sizeof(P9054_DMA_STRUCT));
  713.     if (hDma==NULL)
  714.     {
  715.         sprintf( P9054_ErrorString, "Failed allocating memory for dma handle!\n");
  716.         goto Exit;
  717.     }
  718.     BZERO (*hDma);
  719.     hDma->dmaChannel = dmaChannel;
  720.     hDma->dma.dwBytes = dwBytes;
  721.     hDma->dma.pUserAddr = buf; 
  722.     hDma->dma.dwOptions = 0; 
  723.     WD_DMALock (hPlx->hWD, &hDma->dma);
  724.     if (!hDma->dma.hDma) 
  725.     {
  726.         sprintf( P9054_ErrorString, "Failed locking the buffer!\n");
  727.         goto Exit;
  728.     }
  729.     if (hDma->dma.dwPages==1)
  730.     {
  731.         //dma of one page ==> direct dma
  732.         dwDMAMODE = 
  733.             (fAutoinc ? 0 : BIT11) 
  734.             | BIT6 
  735.             | (mode==P9054_MODE_BYTE ? 0 : mode==P9054_MODE_WORD ? BIT0 : (BIT1 | BIT0));
  736.         dwDMADPR = BIT0 | (fIsRead ? BIT3 : 0);
  737.         dwDMALADR = dwLocalAddr;
  738.  
  739.         P9054_WriteReg (hPlx, P9054_DMAMODE + dwChannelShift, dwDMAMODE);
  740.         P9054_WriteReg (hPlx, P9054_DMAPADR + dwChannelShift, (DWORD) hDma->dma.Page[0].pPhysicalAddr);
  741.         P9054_WriteReg (hPlx, P9054_DMALADR + dwChannelShift, dwDMALADR);
  742.         P9054_WriteReg (hPlx, P9054_DMASIZ + dwChannelShift, hDma->dma.Page[0].dwBytes);
  743.         P9054_WriteReg (hPlx, P9054_DMADPR + dwChannelShift, dwDMADPR);
  744.     }
  745.     else
  746.     {
  747.         DWORD dwAlignShift, dwPageNumber, dwMemoryCopied;
  748.         typedef struct {
  749.             DWORD dwPADR;
  750.             DWORD dwLADR;
  751.             DWORD dwSIZ;
  752.             DWORD dwDPR;
  753.         } DMA_LIST;
  754.         DMA_LIST *pList;
  755.  
  756.         //dma of more then one page ==> chain dma
  757.         hDma->dmaList.dwBytes = hDma->dma.dwPages * sizeof(DMA_LIST) + 0x10; // includes extra 0x10 bytes for quadword alignment
  758.         hDma->dmaList.pUserAddr = NULL;
  759.         hDma->dmaList.dwOptions = DMA_KERNEL_BUFFER_ALLOC;
  760.         WD_DMALock (hPlx->hWD, &hDma->dmaList);
  761.         if (!hDma->dmaList.hDma)
  762.         {
  763.             sprintf (P9054_ErrorString, "Failed allocating the chain buffer!\n");
  764.             goto Exit;
  765.         }
  766.  
  767.         //setting chain of dma pages in the memory
  768.         dwMemoryCopied = 0;
  769.         dwAlignShift = 0x10 - (DWORD) hDma->dmaList.pUserAddr & 0xf;  
  770.         // verifcation that bits 0-3 are zero (quadword aligned)
  771.         pList = (DMA_LIST *) ((DWORD) hDma->dmaList.pUserAddr + dwAlignShift);
  772.         for (dwPageNumber=0; dwPageNumber<hDma->dma.dwPages; dwPageNumber++)
  773.         {
  774.             pList[dwPageNumber].dwPADR = (DWORD) hDma->dma.Page[dwPageNumber].pPhysicalAddr;
  775.             pList[dwPageNumber].dwLADR = dwLocalAddr + (fAutoinc ? dwMemoryCopied : 0);
  776.             pList[dwPageNumber].dwSIZ = hDma->dma.Page[dwPageNumber].dwBytes;
  777.             pList[dwPageNumber].dwDPR = 
  778.                 ((DWORD) hDma->dmaList.Page[0].pPhysicalAddr + dwAlignShift + sizeof(DMA_LIST)*(dwPageNumber+1))
  779.                 | BIT0 | (fIsRead ? BIT3 : 0);
  780.             dwMemoryCopied += hDma->dma.Page[dwPageNumber].dwBytes;
  781.         }
  782.         pList[dwPageNumber - 1].dwDPR |= BIT1; // mark end of chain
  783.     
  784.         dwDMAMODE = (fAutoinc ? 0 : BIT11) 
  785.                     | BIT6
  786.                     | BIT9        // chain transfer
  787.                      | (mode==P9054_MODE_BYTE ? 0 : mode==P9054_MODE_WORD ? BIT0 : (BIT1 | BIT0));
  788.         dwDMADPR = ((DWORD)hDma->dmaList.Page[0].pPhysicalAddr + dwAlignShift) | BIT0; 
  789.         // starting the dma
  790.         P9054_WriteReg (hPlx, P9054_DMAMODE + dwChannelShift, dwDMAMODE);
  791.         P9054_WriteReg (hPlx, P9054_DMADPR + dwChannelShift, dwDMADPR);
  792.     }
  793.  
  794.     return hDma;
  795.  
  796. Exit:
  797.     if (hDma!=NULL)
  798.         P9054_DMAClose(hPlx,hDma);
  799.     return NULL;
  800. }
  801.  
  802. void P9054_DMAClose (P9054_HANDLE hPlx, P9054_DMA_HANDLE hDma)
  803. {
  804.     if (hDma->dma.hDma)
  805.         WD_DMAUnlock(hPlx->hWD, &hDma->dma);
  806.     if (hDma->dmaList.hDma)
  807.         WD_DMAUnlock(hPlx->hWD, &hDma->dmaList);
  808.     free (hDma);
  809. }
  810.  
  811. BOOL P9054_DMAIsDone (P9054_HANDLE hPlx, P9054_DMA_HANDLE hDma)
  812. {
  813.     return (P9054_ReadByte(hPlx, P9054_ADDR_REG, P9054_DMACSR + 
  814.         hDma->dmaChannel) & BIT4) == BIT4;
  815. }
  816.  
  817. void P9054_DMAStart (P9054_HANDLE hPlx, P9054_DMA_HANDLE hDma, BOOL fBlocking)
  818. {
  819.     P9054_WriteByte (hPlx, P9054_ADDR_REG, P9054_DMACSR + hDma->dmaChannel, 
  820.         BIT0 | BIT1);
  821.  
  822.     //Busy wait for plx to finish transfer
  823.     if (fBlocking) 
  824.         while (!P9054_DMAIsDone(hPlx, hDma))
  825.             ;
  826. }
  827.  
  828. BOOL P9054_DMAReadWriteBlock (P9054_HANDLE hPlx, DWORD dwLocalAddr, PVOID buf, 
  829.     DWORD dwBytes, BOOL fIsRead, P9054_MODE mode, P9054_DMA_CHANNEL dmaChannel)
  830. {
  831.     P9054_DMA_HANDLE hDma;
  832.     if (dwBytes==0) 
  833.         return TRUE;
  834.  
  835.     hDma = P9054_DMAOpen(hPlx, dwLocalAddr, buf, dwBytes, fIsRead, mode, dmaChannel);
  836.     if (!hDma) 
  837.         return FALSE;
  838.  
  839.     P9054_DMAStart(hPlx, hDma, TRUE);
  840.     P9054_DMAClose(hPlx, hDma);
  841.     return TRUE;
  842. }
  843.  
  844. BOOL P9054_EEPROMValid(P9054_HANDLE hPlx)
  845. {
  846.     return (P9054_ReadReg(hPlx, P9054_CNTRL) & BIT28)==BIT28;
  847. }
  848.  
  849. BOOL P9054_EEPROMReadWord(P9054_HANDLE hPlx, DWORD dwOffset, PWORD pwData)
  850. {
  851.     DWORD dwData;
  852.     DWORD dwAddr;
  853.  
  854.     if (dwOffset % 2)
  855.     {
  856.         sprintf (P9054_ErrorString, "The offset is not even\n");
  857.         return FALSE;
  858.     }
  859.     dwAddr = dwOffset - (dwOffset % 4);
  860.  
  861.     if (!P9054_EEPROMReadDWord(hPlx, dwAddr, &dwData))
  862.         return FALSE;
  863.  
  864.     *pwData = (WORD) (dwData >> ((dwOffset % 4)*8));
  865.  
  866.     return TRUE;
  867. }
  868.  
  869. BOOL P9054_EEPROMWriteWord(P9054_HANDLE hPlx, DWORD dwOffset, WORD wData)
  870. {
  871.     DWORD dwData;
  872.     DWORD dwAddr;
  873.  
  874.     dwAddr = dwOffset - (dwOffset % 4);
  875.  
  876.     if (!P9054_EEPROMReadDWord(hPlx, dwAddr, &dwData))
  877.         return FALSE;
  878.  
  879.     switch (dwOffset % 4)
  880.     {
  881.     case 0:
  882.         dwData = (dwData & 0xffff0000) | wData;
  883.         break;
  884.     case 2:
  885.         dwData = (dwData & 0x0000ffff) | (wData << 16);
  886.         break;
  887.     default:
  888.         sprintf (P9054_ErrorString, "The offset is not even\n");
  889.         return FALSE;
  890.     }
  891.  
  892.     return P9054_EEPROMWriteDWord(hPlx, dwAddr, dwData);
  893. }
  894.  
  895. void P9054_Sleep(P9054_HANDLE hPlx, DWORD dwMicroSeconds)
  896. {
  897.     WD_SLEEP sleep;
  898.  
  899.     BZERO (sleep);
  900.     sleep.dwMicroSeconds = dwMicroSeconds;
  901.     WD_Sleep( hPlx->hWD, &sleep);
  902. }
  903.  
  904. BYTE P9054_EEPROMEnable(P9054_HANDLE hPlx, WORD addr)
  905. {
  906.     BYTE old_val;
  907.  
  908.     old_val = P9054_ReadByte(hPlx, P9054_ADDR_REG, P9054_PROT_AREA);
  909.     
  910.     addr /= 4;
  911.     addr &= 0x7f;
  912.  
  913.     P9054_WriteByte(hPlx, P9054_ADDR_REG, P9054_PROT_AREA, (BYTE)addr);
  914.     P9054_Sleep(hPlx, 10000);
  915.  
  916.     return old_val * 4; //expand from dwords to bytes
  917. }
  918.  
  919. void P9054_EEPROMDataReadWrite(P9054_HANDLE hPlx, BOOL fIsRead, PDWORD pdwData)
  920. {
  921.     WD_PCI_CONFIG_DUMP pciCnf;
  922.  
  923.     BZERO (pciCnf);
  924.     pciCnf.pciSlot = hPlx->pciSlot;
  925.     pciCnf.pBuffer = pdwData;
  926.     pciCnf.dwOffset = P9054_VPD_DATA;
  927.     pciCnf.dwBytes = 4;
  928.     pciCnf.fIsRead = fIsRead;
  929.     WD_PciConfigDump(hPlx->hWD,&pciCnf);
  930. }
  931.  
  932. void P9054_EEPROMAddrReadWrite(P9054_HANDLE hPlx, BOOL fIsRead, PWORD pwAddr)
  933. {
  934.     WD_PCI_CONFIG_DUMP pciCnf;
  935.  
  936.     BZERO (pciCnf);
  937.     pciCnf.pciSlot = hPlx->pciSlot;
  938.     pciCnf.pBuffer = pwAddr;
  939.     pciCnf.dwOffset = P9054_VPD_ADDR;
  940.     pciCnf.dwBytes = 2;
  941.     pciCnf.fIsRead = fIsRead;
  942.     WD_PciConfigDump(hPlx->hWD,&pciCnf);
  943. }
  944.  
  945. BOOL P9054_EEPROMReadDWord(P9054_HANDLE hPlx, DWORD dwOffset, PDWORD pdwData)
  946. {
  947.     WORD wVal;
  948.     WORD wAddr;
  949.     int i ;
  950.     BOOL fEnd = FALSE ;
  951.  
  952.     if (dwOffset % 4)
  953.     {
  954.         sprintf (P9054_ErrorString, "The offset is not a multiple of 4\n");
  955.         return FALSE;
  956.     }
  957.     wAddr = (((WORD)dwOffset) & (~BIT15)) ;
  958.  
  959.     
  960.     P9054_EEPROMAddrReadWrite(hPlx, FALSE, &wAddr);
  961.  
  962.     P9054_Sleep(hPlx, 10000);
  963.  
  964.     for (i=0; !fEnd && i<100; i++)
  965.     {
  966.         P9054_EEPROMAddrReadWrite(hPlx, TRUE, &wVal);
  967.         if (wVal & BIT15)
  968.             fEnd = TRUE;
  969.         P9054_Sleep(hPlx, 10000);
  970.     }
  971.     
  972.     if (i==100)
  973.     {
  974.         sprintf (P9054_ErrorString, "Acknoledge to EEPROM read was not recived\n");
  975.         return FALSE;
  976.     }
  977.  
  978.     P9054_EEPROMDataReadWrite(hPlx, TRUE, pdwData);
  979.  
  980.     return TRUE;
  981. }
  982.  
  983. BOOL P9054_EEPROMWriteDWord(P9054_HANDLE hPlx, DWORD dwOffset, DWORD dwData)
  984. {
  985.     DWORD dwReadback;
  986.     WORD wAddr;
  987.     WORD wVal;
  988.     int i;
  989.     BOOL fRet;
  990.     BOOL fEnd = FALSE ;
  991.     BOOL fReadOk = FALSE;
  992.     BYTE bEnableOffset;
  993.  
  994.  
  995.     if (dwOffset % 4)
  996.     {
  997.         sprintf (P9054_ErrorString, "The offset is not a multiple of 4\n");
  998.         return FALSE;
  999.     }
  1000.     wAddr = (WORD)dwOffset;
  1001.     bEnableOffset = P9054_EEPROMEnable(hPlx, wAddr);
  1002.     wAddr = wAddr | BIT15;
  1003.  
  1004.     P9054_EEPROMDataReadWrite(hPlx, FALSE, &dwData);
  1005.  
  1006.     P9054_EEPROMAddrReadWrite(hPlx, FALSE, &wAddr);
  1007.  
  1008.     P9054_Sleep(hPlx, 10000);
  1009.     
  1010.     for (i=0; !fEnd && i<100 ;i++)
  1011.     {
  1012.         P9054_EEPROMAddrReadWrite(hPlx, TRUE, &wVal);
  1013.         if ((wVal & BIT15) == 0)
  1014.             fEnd = TRUE;
  1015.         P9054_Sleep(hPlx, 10000);
  1016.     }
  1017.  
  1018.     fReadOk = P9054_EEPROMReadDWord(hPlx, dwOffset, &dwReadback);
  1019.  
  1020.     if (fReadOk && dwReadback==dwData)
  1021.         fRet = TRUE;
  1022.     else
  1023.     {
  1024.         fRet = FALSE;
  1025.         if (fReadOk)
  1026.             sprintf (P9054_ErrorString, "Write 0x%08x, Read 0x%08x\n",dwData, dwReadback);
  1027.         else
  1028.             sprintf (P9054_ErrorString, "Error reading EEPROM\n");
  1029.     }
  1030.     P9054_EEPROMEnable(hPlx, bEnableOffset); 
  1031.     return fRet;
  1032. }
  1033.